

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include "Log.hpp"
#include<string>
#include<pthread.h>
#include<sys/wait.h>
#include"ThreadPool.hpp"
#include"InetAddr.hpp"
#include<cerrno>
#include<signal.h>
#include "Common.hpp"
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include<functional>
#include <cstring>
using namespace std;
using namespace LogModule;
using namespace ThreadPoolModule;
static const uint16_t gport = 8082;
#define BACKLOG 8

using handler_t = function<string(string)>;


class TcpServer
{
    using task_t = function<void()>;
    struct ThreadData
   {
      int sockfd;
      TcpServer* self;
   }; 
  

public:
    TcpServer(handler_t handler,int port = gport)
        : _port(port),
        _isrunning(false),
        _handler(handler)
    {
    }
    ~TcpServer() {}
    void InitServer()
    {
        // 1.创建Tcp socket
        _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0); // Tcp Socket
        if (_listensockfd < 0)                             // 创建套接字失败
        {
            LOG(LogLevel::FATAL) << "socket error\n";
            Die(SOCKET_ERR); // 错误码
        }
        LOG(LogLevel::INFO) << "socket create success,sockfd is : " << _listensockfd << "\n"; // 创建成功
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        // 填充
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);      // 网络通信要主机转网络
        local.sin_addr.s_addr = INADDR_ANY; // 云服务器不允许绑定公网ip,不建议绑定固定ip 这里建议任意地址绑定

        // 2.bind
        int n = ::bind(_listensockfd, CONV(&local), sizeof(local));
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error\n";
            Die(BIND_ERR);
        }
         LOG(LogLevel::INFO) << "bind create success,sockfd is : " << _listensockfd << "\n";
        // 3. c s
        n = ::listen(_listensockfd, BACKLOG);
        if (n < 0) // listen失败
        {
            LOG(LogLevel::FATAL) << "listen error\n";
            Die(LISTEN_ERR);
        }
        LOG(LogLevel::INFO) << "listen create success,sockfd is : " << _listensockfd << "\n";
        //::signal(SIGCHLD,SIG_IGN); //子进程退出,OS会自动回收资源,不用再wait
    }

    void HandlerRequest(int sockfd)
    {
        LOG(LogLevel::INFO) << "HandlerRequest success,sockfd is : " << sockfd << "\n";
         char inbuffer[4096];
         //一直不退出的任务 --- 长任务
        while(true)
        {
          
          //1.先读取请求 --- 面向字节流，tcp更像文件->用read读！
           ssize_t n = ::recv(sockfd,inbuffer,sizeof(inbuffer)-1,0);//实际读到的字节
           if(n > 0)
           {
              LOG(LogLevel::INFO) << inbuffer;
              inbuffer[n] = 0;
            //   //2.读完还要把消息显示回去 TCP也是全双工通信的！ mwrite
            //   string echo_str = "server_echo# ";
            //   echo_str += inbuffer;
            //规定用户发过来完整的命令string
            LOG(LogLevel::DEBUG) << "正在进入hanlder的逻辑...\n";
            string cmd_result = _handler(inbuffer);  
            ::send(sockfd,cmd_result.c_str(),cmd_result.size(),0); //把处理结果返回

           }
           else if(n == 0) //如果读取返回值是0 表示client退出
           {
              LOG(LogLevel::INFO) << "client quit\n";
              break; 
           }
           else //读取失败
           {
               break;
           }
        }
        //回收
        ::close(sockfd);
    }
  //如果是成员函数就有this指针,多了一个参数,我们需要设置为static
    static void* ThreadEntry(void* args) 
    {
        pthread_detach(pthread_self()); //分离主线程就不用关系了
        ThreadData* data = (ThreadData*)args;
        //HandlerRequest(sockfd); //静态成员方法无法访问类内成员 所以我们新建一个类型ThreadData
        data->self->HandlerRequest(data->sockfd);
        return nullptr;
    }

    void Start()
    {
        _isrunning = true;
        while(_isrunning)
        {
            //1.不能直接读数据，要先获取新连接
            struct sockaddr_in peer;
            socklen_t peerlen = sizeof(peer);
            LOG(LogLevel::DEBUG) << "accept ing...\n";
            //获取客户端信息 
            int sockfd = ::accept(_listensockfd,CONV(&peer),&peerlen);
            if(sockfd < 0)
            {
                LOG(LogLevel::WARNING) << "accept error: " << strerror(errno);
                continue;
            }
            //获取连接成功
            LOG(LogLevel::INFO) << "accept success,sockfd is : " << sockfd << "\n";
            InetAddr addr(peer);
            LOG(LogLevel::INFO) << "client info: " << addr.Addr() << "\n";
            // version --0 
            // HandlerRequest(sockfd);

            // //version1 --- 多进程
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     //child
            //     ::close(_listensockfd);
            //     if(fork()>0) exit(0);
            //     HandlerRequest(sockfd);
            //      exit(0);
            // }
            // ::close(sockfd);
            // //等待
            // int rid = ::waitpid(id,nullptr,0);
            // if(rid < 0)
            // {
            //     LOG(LogLevel::WARNING) << "waitpid error\n";
            // }

            // //v3 -- 多线程
            // pthread_t tid;
            // ThreadData* data = new ThreadData;
            // data->sockfd = sockfd;
            // data->self = this;
            // pthread_create(&tid,nullptr,ThreadEntry,data);

           //v4 -- 线程池版本 比较适合处理短任务 或者是用户量较小
           task_t f = std::bind(&TcpServer::HandlerRequest,this,sockfd); //构建任务
           ThreadPool<task_t>::getInstance()->Enqueue([this,sockfd](){
               this->HandlerRequest(sockfd);
           });//入队列
           

        }

    }

    void Stop()
    {

    }

private:
    int _listensockfd; //监听套接字
    uint16_t _port;
    bool _isrunning;
    handler_t _handler;
};
